
#include "xmodule_config.h"

#if MODULE_CHECK_ENABLED( BUTTON )

#include <stdint.h>
#include <stdbool.h> 
#include <string.h>

#include "os_timer.h"
#include "rtl876x_rcc.h"
#include "rtl876x_pinmux.h"
#include "rtl876x_gpio.h"
#include "rtl876x_nvic.h"
#include "em_buttons.h"

#include "kb.h"
#include "boards.h"

#include "xDLPS.h"

#if MODULE_CHECK_LOG_ENABLED( BUTTON )
#include "log.h"
#define LOG     LOG_INFO
#define LOG0    LOG_INFO0 
#define LOG1    LOG_INFO1
#define LOG2    LOG_INFO2
#define LOG3    LOG_INFO3
#define FMT_STR  FORMAT_STRING
#else 
#define LOG(...) 
#define LOG0(...)
#define LOG1(...)
#define LOG2(...)
#define LOG3(...)
#define FMT_STR(...)
#endif 

static bool m_timer_is_started = false; 

KB_DEF( KB_BUTTON, NUMS_OF_BUTTON, NULL);

void* buttonTimer = NULL;
//static uint8_t button_dlps_index;

static const T_IO_MODULE_CBS button_cbs = 
{
    .init = NULL,
    .enter_dlps = em_button_enter_dlps,
    .exit_dlps = em_button_exit_dlps,
    .check_allow_dlps = NULL,
    .system_wakeup_check_allow_dlps = em_button_system_wakeup_dlps_check,
    .name = "button\0",
};

static void gpio_configs(void)
{
    RCC_PeriphClockCmd( APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE ); 

    Pad_Config(KEY0_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE,PAD_OUT_HIGH);    
    Pinmux_Config(KEY0_PIN, DWGPIO);
            
#ifdef KEY1_PIN
    Pad_Config(KEY1_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE,PAD_OUT_LOW);
    Pinmux_Config(KEY1_PIN, DWGPIO);
#endif
    
#ifdef KEY2_PIN
    Pad_Config(KEY2_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE,PAD_OUT_LOW);
    Pinmux_Config(KEY2_PIN, DWGPIO);
#endif 
    
    GPIO_InitTypeDef gpioInitStruct;
    GPIO_StructInit( &gpioInitStruct );
    
    gpioInitStruct.GPIO_Pin             = GPIO_GetPin( KEY0_PIN ); 
    gpioInitStruct.GPIO_Mode            = GPIO_Mode_IN;
    gpioInitStruct.GPIO_ITCmd           = ENABLE;
    gpioInitStruct.GPIO_ITTrigger       = GPIO_INT_Trigger_EDGE;
    gpioInitStruct.GPIO_ITPolarity      = GPIO_INT_POLARITY_ACTIVE_LOW;
    gpioInitStruct.GPIO_ITDebounce      = GPIO_INT_DEBOUNCE_DISABLE;
    gpioInitStruct.GPIO_DebounceTime    = 10; //1ms 
    GPIO_Init( &gpioInitStruct );

#ifdef KEY1_PIN
    GPIO_StructInit( &gpioInitStruct );
    gpioInitStruct.GPIO_Pin             = GPIO_GetPin( KEY1_PIN ); 
    gpioInitStruct.GPIO_Mode            = GPIO_Mode_IN;
    gpioInitStruct.GPIO_ITCmd           = ENABLE;
    gpioInitStruct.GPIO_ITTrigger       = GPIO_INT_Trigger_EDGE;
    gpioInitStruct.GPIO_ITPolarity      = GPIO_INT_POLARITY_ACTIVE_LOW;
    GPIO_Init( &gpioInitStruct ); 
#endif
#ifdef KEY2_PIN
    GPIO_StructInit( &gpioInitStruct );
    gpioInitStruct.GPIO_Pin             = GPIO_GetPin( KEY2_PIN ); 
    gpioInitStruct.GPIO_Mode            = GPIO_Mode_IN;
    gpioInitStruct.GPIO_ITCmd           = ENABLE;
    gpioInitStruct.GPIO_ITTrigger       = GPIO_INT_Trigger_EDGE;
    gpioInitStruct.GPIO_ITPolarity      = GPIO_INT_POLARITY_ACTIVE_LOW;
    GPIO_Init( &gpioInitStruct ); 
#endif
    
    NVIC_InitTypeDef nvicInitStruct; 
    nvicInitStruct.NVIC_IRQChannel      = GPIO_KEY0_IRQn;
    nvicInitStruct.NVIC_IRQChannelPriority = 3;
    nvicInitStruct.NVIC_IRQChannelCmd   = ENABLE;
    NVIC_Init( &nvicInitStruct ); 

#ifdef KEY1_PIN
    nvicInitStruct.NVIC_IRQChannel      = GPIO_KEY1_IRQn;
    nvicInitStruct.NVIC_IRQChannelPriority = 3;
    nvicInitStruct.NVIC_IRQChannelCmd   = ENABLE;
    NVIC_Init( &nvicInitStruct ); 
#endif
#ifdef KEY2_PIN
    nvicInitStruct.NVIC_IRQChannel      = GPIO_KEY2_IRQn;
    nvicInitStruct.NVIC_IRQChannelPriority = 3;
    nvicInitStruct.NVIC_IRQChannelCmd   = ENABLE;
    NVIC_Init( &nvicInitStruct ); 
#endif 
    
   GPIO_INTConfig( GPIO_GetPin( KEY0_PIN ), DISABLE ); 
   GPIO_MaskINTConfig( GPIO_GetPin( KEY0_PIN ), ENABLE ); 
   System_WakeUpPinEnable( KEY0_PIN, PAD_WAKEUP_POL_LOW, PAD_WK_DEBOUNCE_DISABLE); 
    
#ifdef KEY1_PIN
    GPIO_INTConfig( GPIO_GetPin( KEY1_PIN ), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( KEY1_PIN ), ENABLE ); 
    System_WakeUpPinEnable( KEY1_PIN, PAD_WAKEUP_POL_LOW, PAD_WK_DEBOUNCE_DISABLE ); 
#endif
#ifdef KEY2_PIN
    GPIO_INTConfig( GPIO_GetPin( KEY2_PIN ), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( KEY2_PIN ), ENABLE ); 
    System_WakeUpPinEnable( KEY2_PIN, PAD_WAKEUP_POL_LOW, PAD_WK_DEBOUNCE_DISABLE ); 
#endif     
}

void em_button_enter_dlps(void)
{
    Pad_Config( KEY0_PIN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
#ifdef KEY1_PIN
    Pad_Config( KEY1_PIN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
#endif 
#ifdef KEY2_PIN
    Pad_Config( KEY2_PIN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
#endif 
}
void em_button_exit_dlps(void)
{
    Pad_Config( KEY0_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
#ifdef KEY1_PIN
    Pad_Config( KEY1_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
#endif
#ifdef KEY2_PIN
    Pad_Config( KEY2_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
#endif 
}
bool em_button_system_wakeup_dlps_check(void)
{
    if( System_WakeUpInterruptValue( KEY0_PIN) == SET
#ifdef KEY1_PIN
    || System_WakeUpInterruptValue( KEY1_PIN ) == SET
#endif
#ifdef KEY2_PIN
    || System_WakeUpInterruptValue( KEY2_PIN ) == SET
#endif
    )
    {
        Pad_ClearWakeupINTPendingBit( KEY0_PIN ); 
#ifdef KEY1_PIN
        Pad_ClearWakeupINTPendingBit( KEY1_PIN ); 
#endif
#ifdef KEY2_PIN
        Pad_ClearWakeupINTPendingBit( KEY2_PIN ); 
#endif 
        return true; 
    }
    
    return false; 
}

void GPIO_KEY0_IRQ_HANDLER(void)
{
    GPIO_INTConfig( GPIO_GetPin( KEY0_PIN ), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( KEY0_PIN ), ENABLE );

    if( buttonTimer != NULL ) 
    {
        if( m_timer_is_started == false ) 
        {
            os_timer_start(&buttonTimer);
            m_timer_is_started = true;
            LOG("[BUTTON]: timer start");
        }
    }

    GPIO_ClearINTPendingBit( GPIO_GetPin( KEY0_PIN ) );   
    // GPIO_INTConfig( GPIO_GetPin(KEY0_PIN), ENABLE );
    // GPIO_MaskINTConfig( GPIO_GetPin(KEY0_PIN), DISABLE );
}
#ifdef KEY1_PIN
void GPIO_KEY1_IRQ_HANDLER(void)
{    
    GPIO_INTConfig( GPIO_GetPin( KEY1_PIN ), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( KEY1_PIN ), ENABLE ); 
    GPIO_ClearINTPendingBit( GPIO_GetPin( KEY1_PIN ) );
    
    if( buttonTimer != NULL ) 
    {
        if( m_timer_is_started == false ) 
        {
            //xTimerStartFromISR( buttonTimer, 0 );
            os_timer_start(&buttonTimer);
            m_timer_is_started = true;
            
//            LOG("[BUTTON]: timer start");
        }
    }   
}
#endif

#ifdef KEY2_PIN
void GPIO_KEY2_IRQ_HANDLER(void)
{
    GPIO_INTConfig( GPIO_GetPin( KEY2_PIN ), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( KEY2_PIN ), ENABLE ); 
    GPIO_ClearINTPendingBit( GPIO_GetPin( KEY2_PIN ) );
    if( buttonTimer != NULL ) 
    {
        if( m_timer_is_started == false ) 
        {
            //xTimerStartFromISR( buttonTimer, 0 );
            os_timer_start(&buttonTimer);
            m_timer_is_started = true;
        }
    }
}
#endif 

static void button_timer_timeout_handler( void* xTimer )
{
    LOG1("[%s]: timer timeout \r\n", FMT_STR( __FUNCTION__ ) );
    
    uint32_t flag = em_buttons_get_pin_state();
    if( kb_process( &KB_BUTTON, flag) > 0 )
    {
        GPIO_INTConfig( GPIO_GetPin(KEY0_PIN), ENABLE );
        GPIO_MaskINTConfig( GPIO_GetPin(KEY0_PIN), DISABLE );
        GPIO_ClearINTPendingBit( GPIO_GetPin(KEY0_PIN) );

#ifdef KEY1_PIN
        GPIO_INTConfig( GPIO_GetPin(KEY1_PIN), ENABLE );
        GPIO_MaskINTConfig( GPIO_GetPin(KEY1_PIN), DISABLE );
        GPIO_ClearINTPendingBit( GPIO_GetPin(KEY1_PIN) );
#endif 

#ifdef KEY2_PIN
        GPIO_INTConfig( GPIO_GetPin(KEY2_PIN), ENABLE );
        GPIO_MaskINTConfig( GPIO_GetPin(KEY2_PIN), DISABLE );
        GPIO_ClearINTPendingBit( GPIO_GetPin(KEY2_PIN) );
#endif
        
        m_timer_is_started = false;
        os_timer_stop(&buttonTimer);
        LOG("[BUTTON]: timer stop");        
    }
}

void em_buttons_init(void)
{
    gpio_configs();
    if( buttonTimer == NULL ) 
    {
        os_timer_create( &buttonTimer, "button_timer", 0, 20, true, button_timer_timeout_handler );
    } 
    

}
void em_buttons_init_dlps(void)
{
    /*button_dlps_index = */
    uint32_t index = xDLPS_register( &button_cbs );
    LOG1("[BUTTON]: DPLS flag = %d\r\n", index );
}

void em_buttons_start(void)
{
    m_timer_is_started = true; 
    os_timer_start(&buttonTimer);
}

void em_buttons_stop(void)
{
    
}

uint32_t em_buttons_get_pin_state(void)
{
    uint32_t flag = 0;
    
    if( GPIO_ReadInputDataBit( GPIO_GetPin(KEY0_PIN) ) == 0 ) 
    {
        flag |= 0x01;
    }

#ifdef KEY1_PIN
    if( GPIO_ReadInputDataBit( GPIO_GetPin(KEY1_PIN) ) == 0 ) 
    {
        flag |= 0x02; 
    }
#endif
    
#ifdef KEY2_PIN
    if( GPIO_ReadInputDataBit( GPIO_GetPin(KEY2_PIN) ) == 0 ) 
    {
        flag |= 0x04; 
    }
#endif 
    
    return flag; 
}

void em_buttons_register_callback( kb_evt_handle_t evt_handle )
{
    KB_BUTTON.handle = evt_handle; 
}

#endif 
